package mylittleinvestigations;

import mylittleinvestigations.GameUi.PartnerInformation;
import mylittleinvestigations.GameUi.Arrow;
import mylittleinvestigations.GameUi.ArrowDirection;
import java.util.ArrayList;
import java.util.Arrays;
import mylittleinvestigations.EasingFunctions.EasingFunction;
import mylittleinvestigations.EasingFunctions.LinearEase;
import mylittleinvestigations.PersistentThreads.RenderThread;
import org.dawnmew.jpurewave.SoundSystem;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.UnicodeFont;
import org.newdawn.slick.geom.Rectangle;

public class Notification
{
    private final int AnimationDuration = 200;
    private final int PartnerAnimationDelay = 200;

    private static Rectangle textAreaRect;
    private static float desiredPadding;
    private static UnicodeFont textFont;

    private ArrayList<String> textLines;
    private ArrayList<Vector2> textLinePositions;
    private PartnerInformation partnerInformation;
    private Arrow downArrow;
    private int animationOffsetText;
    private int animationOffsetPartner;
    private EasingFunction inEaseText;
    private EasingFunction inEasePartner;
    private EasingFunction outEaseText;
    private EasingFunction outEasePartner;
    private String notificationSoundEffect = "";

    public String getNotificationSoundEffect()
    {
        if (this.notificationSoundEffect.equals(""))
        {
            this.notificationSoundEffect = (this.partnerInformation != null ? "NewPartner" : "NewAddition");
        }

        return this.notificationSoundEffect;
    }

    public static void Initialize(
        int textAreaLeft,
        int textAreaTop,
        int textAreaWidth,
        int textAreaHeight,
        float desiredPadding,
        UnicodeFont textFont)
    {
        Notification.textAreaRect = new Rectangle(textAreaLeft, textAreaTop, textAreaWidth, textAreaHeight);
        Notification.desiredPadding = desiredPadding;
        Notification.textFont = textFont;
    }

    public Notification(String rawNotificationText)
    {
        this(rawNotificationText, null);
    }

    public Notification(String rawNotificationText, String partnerId)
    {
        this.textLines = new ArrayList<String>();
        this.textLinePositions = new ArrayList<Vector2>();

        double allowedWidth = textAreaRect.getWidth() - desiredPadding * 2;
        ArrayList<String> wordList = new ArrayList<String>(Arrays.asList(rawNotificationText.split(" ")));

        while (wordList.size() > 0)
        {
            String curString = "";
            double curTextWidth = 0;
            boolean lineDone = false;
            boolean addSpace = false;

            while (!lineDone)
            {
                String curWord = (addSpace ? " " : "") + wordList.get(0);
                double curStringWidth = textFont.getWidth(curWord);

                if (curTextWidth + curStringWidth < allowedWidth)
                {
                    curString += curWord;
                    curTextWidth += curStringWidth;
                    wordList.remove(0);
                    addSpace = true;

                    if (wordList.isEmpty())
                    {
                        lineDone = true;
                    }
                }
                else
                {
                    lineDone = true;
                }
            }

            this.textLines.add(curString);
        }

        float yPosition = textAreaRect.getY() + textAreaRect.getHeight() / 2;

        for (int i = 0; i < this.textLines.size(); i++)
        {
            yPosition -= textFont.getHeight(this.textLines.get(i)) / 2;
        }

        for (int i = 0; i < this.textLines.size(); i++)
        {
            Vector2 textLineSize = new Vector2(textFont.getWidth(this.textLines.get(i)), textFont.getHeight(this.textLines.get(i)));
            this.textLinePositions.add(new Vector2(textAreaRect.getX() + textAreaRect.getWidth() / 2 - textLineSize.getX() / 2, yPosition));
            yPosition += textLineSize.getY();
        }

        if (partnerId != null)
        {
            this.partnerInformation = new PartnerInformation();
            this.partnerInformation.setPartnerId(partnerId);
        }

        this.downArrow = new Arrow(927, 505, ArrowDirection.Down, 10 /* bounceDistance */, false /* isClickable */);
        this.inEaseText = new LinearEase(Settings.DisplayBounds.getX(), 0, AnimationDuration);

        if (partnerId != null)
        {
            this.inEaseText.setAnimationStartDelay(PartnerAnimationDelay);
        }

        this.inEasePartner = new LinearEase(Settings.DisplayBounds.getX(), 0, AnimationDuration);
        this.outEaseText = new LinearEase(0, -Settings.DisplayBounds.getX(), AnimationDuration);

        if (partnerId != null)
        {
            this.outEaseText.setAnimationStartDelay(PartnerAnimationDelay);
        }

        this.outEasePartner = new LinearEase(0, -Settings.DisplayBounds.getX(), AnimationDuration);
    }
    
    private boolean isFinished;
    
    public boolean getIsFinished() { return this.isFinished; }
    public void setIsFinished(boolean isFinished) { this.isFinished = isFinished; }

    public void Begin()
    {
        this.setIsFinished(false);
        SoundSystem.getInstance().playSound(getNotificationSoundEffect());
        this.animationOffsetText = (int)Settings.DisplayBounds.getX();
        this.animationOffsetPartner = (int)Settings.DisplayBounds.getX();
        this.inEaseText.Begin();
        this.inEasePartner.Begin();
    }

    public void Update(GameContainer gc, int delta)
    {
        if ((this.outEaseText.getIsStarted() && !this.outEaseText.getIsFinished()) ||
            (this.outEasePartner.getIsStarted() && !this.outEasePartner.getIsFinished()))
        {
            if (this.outEaseText.getIsStarted() && !this.outEaseText.getIsFinished())
            {
                this.outEaseText.Update(gc, delta);
                this.animationOffsetText = (int)this.outEaseText.GetCurrentValue();
            }

            if (this.outEasePartner.getIsStarted() && !this.outEasePartner.getIsFinished())
            {
                this.outEasePartner.Update(gc, delta);
                this.animationOffsetPartner = (int)this.outEasePartner.GetCurrentValue();
            }
        }
        else if (this.outEaseText.getIsFinished() && this.outEasePartner.getIsFinished())
        {
            this.setIsFinished(true);
        }
        else if ((this.inEaseText.getIsStarted() && !this.inEaseText.getIsFinished()) ||
            (this.inEasePartner.getIsStarted() && !this.inEasePartner.getIsFinished()))
        {
            if (this.inEaseText.getIsStarted() && !this.inEaseText.getIsFinished())
            {
                this.inEaseText.Update(gc, delta);
                this.animationOffsetText = (int)this.inEaseText.GetCurrentValue();
            }

            if (this.inEasePartner.getIsStarted() && !this.inEasePartner.getIsFinished())
            {
                this.inEasePartner.Update(gc, delta);
                this.animationOffsetPartner = (int)this.inEasePartner.GetCurrentValue();
            }
        }
        else
        {
            this.downArrow.Update(gc, delta);

            if (MouseHelper.ClickedAnywhere())
            {
                this.outEaseText.Begin();
                this.outEasePartner.Begin();
            }
        }
    }

    public void Draw(GameContainer gc, Graphics g, float yOffset)
    {
        if (this.inEaseText.getIsFinished() && this.inEasePartner.getIsFinished() && !this.outEaseText.getIsStarted() && !this.outEasePartner.getIsStarted())
        {
            this.downArrow.Draw(gc, g, yOffset);
        }

        for (int i = 0; i < this.textLines.size(); i++)
        {
            Vector2 textLinePosition = this.textLinePositions.get(i);
            
            RenderThread.getInstance().AddStringToRenderQueue(textFont, (float)textLinePosition.getX() + this.animationOffsetText, (float)textLinePosition.getY() + yOffset, this.textLines.get(i));
        }

        if (this.partnerInformation != null)
        {
            this.partnerInformation.Draw(gc, g, this.animationOffsetPartner, yOffset);
        }
    }

    public void Reset()
    {
        this.setIsFinished(false);
        this.downArrow.Reset();
        this.inEaseText.Reset();
        this.inEasePartner.Reset();
        this.outEaseText.Reset();
        this.outEasePartner.Reset();
    }
}